﻿
Imports std

Public Class unhealth_slice_wrapper
    Inherits slice_wrapper

    Private ReadOnly set_unhealth As Boolean = False
    Private _unhealth As singleentry
    Private _full As singleentry

    Public Sub New(ByVal s As islice, ByVal set_unhealth As Boolean)
        MyBase.New(s)
        Me.set_unhealth = set_unhealth
        AddHandler centrosphere.start, AddressOf start_full_check
    End Sub

    Private Sub setfull()
        _full.mark_in_use()
    End Sub

    Private Sub setnotfull()
        _full.mark_not_in_use()
    End Sub

    Private Sub setunhealth()
        If _unhealth.mark_in_use() Then
            startheartbeat()
        End If
    End Sub

    Private Sub start_full_check()
        Dim ec As eventComb = Nothing
        Dim p As pointer(Of Boolean) = Nothing
        p = New pointer(Of Boolean)()
        assert_begin(New eventComb(Function() As Boolean
                                       p.set(False)
                                       ec = slice.full(p)
                                       Return waitfor(ec) AndAlso
                                              goto_next()
                                   End Function,
                                   Function() As Boolean
                                       If ec.end_result() AndAlso Not (+p) Then
                                           setnotfull()
                                       ElseIf Not ec.end_result() OrElse (+p) Then
                                           setfull()
                                       End If
                                       Return waitfor(10000) AndAlso
                                              goto_prev()
                                   End Function))
    End Sub

    Private Sub startheartbeat()
        Dim ec As eventComb = Nothing
        Dim p As pointer(Of Boolean) = Nothing
        p = New pointer(Of Boolean)()
        raiseError("start heartbeat")
        assert_begin(New eventComb(Function() As Boolean
                                       p.set(False)
                                       ec = slice.heartbeat(p)
                                       Return waitfor(ec) AndAlso
                                              goto_next()
                                   End Function,
                                   Function() As Boolean
                                       If ec.end_result() AndAlso (+p) Then
                                           raiseError("heartbeat succeeded")
                                           sethealth()
                                           Return goto_end()
                                       Else
                                           raiseError(errorHandle.errorType.warning, "heartbeat failed")
                                           Return goto_prev()
                                       End If
                                   End Function))
    End Sub

    Private Sub sethealth()
        _unhealth.mark_not_in_use()
    End Sub

    Private Overloads Function full() As Boolean
        Return _full.in_use()
    End Function

    Public Function unhealth() As Boolean
        If set_unhealth Then
            Return _unhealth.in_use()
        Else
            Return False
        End If
    End Function

    Protected Overrides Function workon(ByVal d As _do(Of eventComb)) As eventComb
        assert(Not d Is Nothing)
        Dim ec As eventComb = Nothing
        Return New eventComb(Function() As Boolean
                                 If unhealth() Then
                                     Return goto_end()
                                 Else
                                     ec = d()
                                     Return waitfor(ec) AndAlso
                                            goto_next()
                                 End If
                             End Function,
                             Function() As Boolean
                                 If Not ec.end_result() Then
                                     If set_unhealth Then
                                         setunhealth()
                                     End If
                                 End If
                                 Return goto_end()
                             End Function)
    End Function

    Private Function workon_not_full(ByVal d As _do(Of eventComb)) As eventComb
        assert(Not d Is Nothing)
        Return workon(Function() As eventComb
                          Dim ec As eventComb = Nothing
                          Return New eventComb(Function() As Boolean
                                                   If full() Then
                                                       Return goto_end()
                                                   Else
                                                       ec = d()
                                                       Return waitfor(ec) AndAlso
                                                              goto_next()
                                                   End If
                                               End Function,
                                               Function() As Boolean
                                                   Return ec.end_result() AndAlso
                                                          goto_end()
                                               End Function)
                      End Function)
    End Function

    Private Overloads Function workon(Of T)(ByVal result As pointer(Of T),
                                            ByVal d As _do(Of pointer(Of T), eventComb),
                                            ByVal final As _do(Of Boolean, T, Boolean)) As eventComb
        assert(Not d Is Nothing)
        assert(Not final Is Nothing)
        Return workon(Function() As eventComb
                          Dim ec As eventComb = Nothing
                          Dim p As pointer(Of T) = Nothing
                          Return New eventComb(Function() As Boolean
                                                   p = New pointer(Of T)()
                                                   ec = d(p)
                                                   Return waitfor(ec) AndAlso
                                                          goto_next()
                                               End Function,
                                               Function() As Boolean
                                                   Return eva(result, +p) AndAlso
                                                          final(ec.end_result(), +p) AndAlso
                                                          ec.end_result() AndAlso
                                                          goto_end()
                                               End Function)
                      End Function)
    End Function

    Private Overloads Function workon(Of T)(ByVal result As pointer(Of T),
                                            ByVal d As _do(Of pointer(Of T), eventComb),
                                            ByVal final As _do(Of T, Boolean)) As eventComb
        assert(Not final Is Nothing)
        Return workon(result, d,
                      Function(ByRef b As Boolean, ByRef p As T) As Boolean
                          Return Not b OrElse final(p)
                      End Function)
    End Function

    Private Overloads Function workon(ByVal result As pointer(Of Boolean),
                                      ByVal d As _do(Of pointer(Of Boolean), eventComb),
                                      ByVal expected As Boolean,
                                      ByVal final As _do(Of Boolean)) As eventComb
        assert(Not final Is Nothing)
        Return workon(result, d,
                      Function(ByRef b As Boolean) As Boolean
                          Return b <> expected OrElse final()
                      End Function)
    End Function

    Private Overloads Function workon(ByVal result As pointer(Of Boolean),
                                      ByVal d As _do(Of pointer(Of Boolean), eventComb),
                                      ByVal expected As Boolean,
                                      ByVal final As void) As eventComb
        assert(Not final Is Nothing)
        Return workon(result, d, expected,
                      Function() As Boolean
                          final()
                          Return True
                      End Function)
    End Function

    Public Overrides Function delete(ByVal key As String,
                                     ByVal result As pointer(Of Boolean)) As eventComb
        Return workon(result, Function(ByRef r) slice.delete(key, r), True, AddressOf setnotfull)
    End Function

    Public Overrides Function empty(ByVal result As pointer(Of Boolean)) As eventComb
        Return workon(result, Function(ByRef r) slice.empty(r), True, AddressOf setnotfull)
    End Function

    Public Overrides Function full(ByVal result As pointer(Of Boolean)) As eventComb
        Return workon(result, Function(ByRef r) slice.full(r), True, AddressOf setfull)
    End Function

    Private Function wm(ByVal result As pointer(Of Boolean),
                        ByVal d As _do(Of pointer(Of Boolean), eventComb)) As eventComb
        assert(Not d Is Nothing)
        Dim p As pointer(Of Boolean) = Nothing
        Dim ec As eventComb = Nothing
        Return workon_not_full(Function() As eventComb
                                   Return New eventComb(Function() As Boolean
                                                            p = New pointer(Of Boolean)()
                                                            ec = d(p)
                                                            Return waitfor(ec) AndAlso
                                                                   goto_next()
                                                        End Function,
                                                        Function() As Boolean
                                                            If ec.end_result() Then
                                                                If Not +p Then
                                                                    setfull()
                                                                End If
                                                                Return eva(result, +p) AndAlso
                                                                       goto_end()
                                                            Else
                                                                Return False
                                                            End If
                                                        End Function)
                               End Function)
    End Function

    Public Overrides Function modify(ByVal key As String,
                                     ByVal buff As bytes,
                                     ByVal ts As Int64,
                                     ByVal result As pointer(Of Boolean)) As eventComb
        Return wm(result, Function(ByRef r) slice.modify(key, buff, ts, r))
    End Function

    Public Overrides Function retire(ByVal result As pointer(Of Boolean)) As eventComb
        Return workon(result, Function(ByRef r) slice.retire(r), True, AddressOf setnotfull)
    End Function

    Public Overrides Function uniqueWrite(ByVal key As String,
                                          ByVal buff As bytes,
                                          ByVal ts As Int64,
                                          ByVal result As pointer(Of Boolean)) As eventComb
        Return workon_not_full(Function() As eventComb
                                   Return slice.uniqueWrite(key, buff, ts, result)
                               End Function)
    End Function

    Public Overrides Function write(ByVal key As String,
                                    ByVal buff As bytes,
                                    ByVal ts As Int64,
                                    ByVal result As pointer(Of Boolean)) As eventComb
        Return wm(result, Function(ByRef r) slice.write(key, buff, ts, r))
    End Function

    Public Overrides Function heartbeat(ByVal result As pointer(Of Boolean)) As eventComb
        assert(False)
        Return Nothing
    End Function
End Class
